package eu.briano.suirvellancecamera.service;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;


import eu.briano.suirvellancecamera.AcquireVideo;
import eu.briano.suirvellancecamera.AlarmNotifier;
import eu.briano.suirvellancecamera.ImageProcessing;
import eu.briano.suirvellancecamera.Log;
import eu.briano.suirvellancecamera.OnImageReady;
import eu.briano.suirvellancecamera.R;
import eu.briano.suirvellancecamera.Utils;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.os.Binder;
import android.os.IBinder;

import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

public class AcquireService extends Service {
	private NotificationManager mNM;
	private int NOTIFICATION = R.string.background_service_started;



	public class LocalBinder extends Binder {
		public AcquireService getService() {
			return AcquireService.this;
		}
	}

	protected boolean taskRunning = false;
	private long nextTimeLapsed = Utils.nowRounded(Utils.timeLapseIntervalMinutes)
						+Utils.timeLapseIntervalMinutes*60*1000;
	
	private AcquireVideo a;
	private ImageProcessing ip;
	private Camera c;

	private final IBinder mBinder = new LocalBinder();

	@Override
	public void onCreate() {
		mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		showNotification();
		Log.i(Utils.logName, "Service onCreate");
		notifier = new AlarmNotifier(this);
		startCamera();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i(Utils.logName, "Service Received start id " + startId + ": "
				+ intent);
		return START_STICKY;
	}

	@Override
	public void onDestroy() {
		mNM.cancel(NOTIFICATION);
		Toast.makeText(this, R.string.background_service_stopped,
				Toast.LENGTH_SHORT).show();
		stopCamera();
		Log.i(Utils.logName, "Service onDestroy");
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.i(Utils.logName, "Service binded");
		return mBinder;
	}

	

	private void startCamera() {
		a = new AcquireVideo(c);
		ip = new ImageProcessing();
		a.setOnImageReady(new OnImageReady() {
			@Override
			public void callBack(int w,int h,byte [] object,Context context) {
				process(w,h,object,context);
			}
		});
		
		c = Camera.open();
		a.setCamera(c);
	
		SurfaceView surfaceView = new SurfaceView(this);// (SurfaceView)findViewById(R.id.preview);
		SurfaceHolder holder = surfaceView.getHolder();
		holder.addCallback((AcquireVideo)a);
		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		
		a.start(null);
		
		try {
			c.setPreviewDisplay(holder);
			c.startPreview();
		} catch (Throwable e) {
			Log.e(Utils.logName,"UploadService on surfaceCreated",e);
		}		
		
	
		
	}

	private void stopCamera() {
		try {
			if (c != null)
				a.stop(null);
				c.release();
		} catch (Exception e) {
	
		}
	}

	Bitmap display = Bitmap.createBitmap(Utils.ipSize, Utils.ipSize,Bitmap.Config.ARGB_8888);
	private AlarmNotifier notifier;

	private int [][][] image = new int [Utils.ipSize][Utils.ipSize][3];
	private int [][][] yuvImage = new int [Utils.ipSize][Utils.ipSize][3];	

	synchronized private void process(int bW, int bH,byte[] buffer,OnImageReady.Context cx) {
	
		try {
		
			Log.v(Utils.logName, "\t\tprocess start at "+(Utils.now()-cx.processStartTs));
			int w = Utils.ipSize;
			int h = w;
				
			boolean doProcessing = true;
			if (buffer != null) {
					
				ip.resizeYUV(bW,bH,buffer,image);
				Log.v(Utils.logName, "resizeYUV at "+(Utils.now()-cx.processStartTs));
				ip.writeBitMapYUVToArrayF(image, yuvImage);
				Log.v(Utils.logName, "writeBitMapYUVToArrayF at "+(Utils.now()-cx.processStartTs));
				if (doProcessing) {
					ip.calculateBckYUV(w, h, yuvImage);
					Log.v(Utils.logName, "calculateBckYUV at "+(Utils.now()-cx.processStartTs));
					//binary on green
					ip.diffBackGroundYUV(w, h, yuvImage,image);
					Log.v(Utils.logName, "diffBackGroundYUV at "+(Utils.now()-cx.processStartTs));
					ip.calculateNoiseMoving(w, h, image);
					Log.v(Utils.logName, "calculateNoiseMoving at "+(Utils.now()-cx.processStartTs));
					ip.snoozeNoiseZone(w, h, image);
					Log.v(Utils.logName, "snoozeNoiseZone at "+(Utils.now()-cx.processStartTs));
					ip.removeSparkle(w, h, image);			
					Log.v(Utils.logName, "removeSparkle at "+(Utils.now()-cx.processStartTs));
	
					float change = ip.pow(image);
					Log.v(Utils.logName, "change at "+(Utils.now()-cx.processStartTs));
					Log.v(Utils.logName, "changed is "+change);
					Log.v(Utils.logName, "estimation done at "+(Utils.now()-cx.processStartTs));
					ip.writeArrayToBitMap(image,display);
	
	
					if (     change > Utils.maxChange ||
						 Utils.now() > nextTimeLapsed) {
						if (Utils.now() > nextTimeLapsed) {
							nextTimeLapsed = Utils.nowRounded(Utils.timeLapseIntervalMinutes)+Utils.timeLapseIntervalMinutes*60*1000;
							Log.v(Utils.logName, "nextTimeLapsed  next " + new Date(nextTimeLapsed).toString());
						}
						cx.imageChange = change;
						notifier.sendAlarm(buffer, Utils.previewFormat, bW, bH,display,cx);
					}
				} else
					ip.writeArrayToBitMap(image,display);
				Log.v(Utils.logName, "process done in"+(Utils.now()-cx.processStartTs));
			}
	
		} catch (Exception e) {
			Log.e(Utils.logName,"process error ",e);
		}
		Log.v(Utils.logName,"processed in "+(Utils.now()-cx.processStartTs));
	}

	

	

	
	private void showNotification() {
		Toast.makeText(this, R.string.background_service_started,
				Toast.LENGTH_SHORT).show();
		/*
		 * Notification notification = new Notification(R.drawable.icon, text,
		 * System.currentTimeMillis());
		 * 
		 * PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new
		 * Intent(this, SuirvellanceCameraActivity.class), 0);
		 * notification.setLatestEventInfo(this,
		 * getText(R.string.background_service_label), text, contentIntent);
		 * 
		 * mNM.notify(NOTIFICATION, notification);
		 */
	}

}
